package com.guo.dms.common.shiro.realms;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.guo.dms.common.menu.dao.MenuDao;
import com.guo.dms.common.menu.entity.Menu;
import com.guo.dms.common.shiro.entity.ShiroUser;
import com.guo.dms.dept.permission.dao.PermssionDao;
import com.guo.dms.dept.permission.entity.Permission;
import com.guo.dms.dept.role.dao.RoleDao;
import com.guo.dms.dept.role.entity.Role;
import com.guo.dms.dept.user.dao.UserDao;
import com.guo.dms.dept.user.entity.User;

/**
 * 权限认证realms
 * 
 * @author Administrator
 *
 */
@Component("shiroUserRealm")
@Lazy(false)
public class ShiroUserRealm extends AuthorizingRealm {
	@Autowired
	private UserDao userDao;
	
	@Autowired
	private RoleDao roleDao;
	
	@Autowired
	private PermssionDao permssionDao;
	
	@Autowired
	private MenuDao menuDao;
	
 	/**
	 * AuthenticationInfo代表了用户的角色信息集合
	 * ,登录时调用. 
	 * 提供账户信息返回认证信息
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//1. 把 AuthenticationToken 转换为 UsernamePasswordToken
	     UsernamePasswordToken upToken = (UsernamePasswordToken)token;
	     String tkusername = upToken.getUsername();
	     User user=null;
	     try{
	    	 user=userDao.selectUserByUserName(tkusername);
	     }catch(Exception e){
	    	 e.printStackTrace();
	     }
	     if(user==null){
	    	  // 用户名不存在抛出异常
	          throw new UnknownAccountException();
	     }
	     /*if(user.getLocked == 0 ){
	    	 // 用户被管理员锁定抛出异常
	            throw new LockedAccountException();
	     }*/
	    //封装认证信息  
	    //SimpleHash MD5password=getMD5Password(password ); 
	    SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(new ShiroUser(user),user.getPassword(), getName());
		return info;
	}
	
	/**
	 * 权限认证   AuthorizationInfo代表了角色的权限信息集合
	 *  
     * 提供用户信息返回权限信息
     *  授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.在配有缓存的情况下，只加载一次. 
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		 //获取roles
		 List<Role>  roles=roleDao.selectRoleByUser(shiroUser.getUser().getId());
		 List<Integer> roleIds=roleDao.selectRoleIdByUser(shiroUser.getUser().getId());
		 //获取permissions
		 List<Permission> permissions=permssionDao.selectPermissionByRoles(roleIds);
		 Set<String> permissionSet=ShiroUser.getPermissionSet(permissions);
		 
		 //获取menus
		 List<Menu>  menus=menuDao.selectMenuByPermission( new ArrayList<String>(permissionSet) );   
		 shiroUser.setRoles(roles);
		 shiroUser.setPermissions(permissions);
		 shiroUser.setMenus(menus);
		 
		 System.out.println("shiroUser inited : roles permissions menus");
		 
		//将这些信息传递给shiro 交给shiro来管理
		SimpleAuthorizationInfo  info=new SimpleAuthorizationInfo( ShiroUser.getRoleNameSet(roles) );
		//使用权限 登陆过后的验证权限 作用是在登陆系统后立即加载本方法（验证）
		   permissionSet.add("use"); 
		info.setStringPermissions( permissionSet );
		return info;
	}
	
	
	/**
	 * 获取加密序列
	 * @param userName
	 * @param password
	 * @return
	 */
	private  SimpleHash getMD5Password(String password){
		//2). credentials: 密码. 
		String hashAlgorithmName = "MD5";
		int hashIterations = 1024;
		return  new SimpleHash(hashAlgorithmName, password,null ,hashIterations);
	}
	 
}
